package com.example.JavaWebApi.core.jwthelper;

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.example.JavaWebApi.core.apiinterceptors.annotation.Authorize;
import com.example.JavaWebApi.core.commonmodel.ResponseTypeEnum;
import com.example.JavaWebApi.model.configmodel.JwtProp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @PROJECT_NAME: JavaWebApi
 * @DESCRIPTION: Jwt帮助类
 * @Author: YangZe
 * @DATE: 2021/11/28 16:28
 */
@Component
public class JwtHelper {
    private static JwtProp staticJwtProp;
    @Autowired
    public void init(JwtProp jwtProp){
        JwtHelper.staticJwtProp=jwtProp;
    }
    /**
     *@Description: 构造token
     *@Param: []
     *@return: java.lang.String
     *@Author: YangZe
     *@date: 2021/11/28
     */
    public static String createToken(){
        Date iatDate = new Date();
        Calendar nowTime = Calendar.getInstance();
        nowTime.add(Calendar.MINUTE,staticJwtProp.getExpiredTime());
        Date expiresDate = nowTime.getTime();
        Algorithm sign=Algorithm.HMAC256(staticJwtProp.getIssuerSigningKey());
        JWTCreator.Builder builder= JWT.create()
                .withAudience(staticJwtProp.getValidAudience())
                .withIssuer(staticJwtProp.getValidIssuer())
                .withIssuedAt(iatDate)
                .withExpiresAt(expiresDate);
        return builder.sign(sign);
    }
    /**
     *@Description: 构造token
     *@Param: [Payload]
     *@return: java.lang.String
     *@Author: YangZe
     *@date: 2021/11/28
     */
    public static String createToken(HashMap<String,String> Payload){

        Date iatDate = new Date();
        Calendar nowTime = Calendar.getInstance();
        nowTime.add(Calendar.MINUTE,staticJwtProp.getExpiredTime());
        Date expiresDate = nowTime.getTime();
        Algorithm sign=Algorithm.HMAC256(staticJwtProp.getIssuerSigningKey());
        JWTCreator.Builder builder= JWT.create()
                .withAudience(staticJwtProp.getValidAudience())
                .withIssuer(staticJwtProp.getValidIssuer())
                .withIssuedAt(iatDate)
                .withNotBefore(iatDate)
                .withExpiresAt(expiresDate);
        for (String key:Payload.keySet()) {
            builder.withClaim(key,Payload.get(key));
        }
        return builder.sign(sign);
    }
    public static Tuple<Boolean, ResponseTypeEnum> verifyToken(String Token, Authorize authorize){
        Tuple<Boolean, ResponseTypeEnum> res=new Tuple<>();
        try{
            boolean VerifyFlag=true;
            DecodedJWT decodedJWT=JWT.decode(Token);
            if (staticJwtProp.isValidateAudience()){
                VerifyFlag=VerifyFlag&& decodedJWT.getAudience().get(0).equals(staticJwtProp.getValidAudience());
            }
            if (staticJwtProp.isValidateIssuer()){
                VerifyFlag=VerifyFlag&& decodedJWT.getIssuer().equals(staticJwtProp.getValidIssuer());
            }
            res.setItem(VerifyFlag);
            if (!VerifyFlag){
                res.setItem1(ResponseTypeEnum.IllegalToken);
                return res;
            }
            if (staticJwtProp.isValidateLifetime()){
                VerifyFlag=VerifyFlag&& decodedJWT.getExpiresAt().after(new Date());
            }
            res.setItem(VerifyFlag);
            if (!VerifyFlag){
                res.setItem1(ResponseTypeEnum.OverdueToken);
            }
            else {
                if (staticJwtProp.isValidateIssuerSigningKey()){
                    JWTVerifier verifier = JWT.require(Algorithm.HMAC256(staticJwtProp.getIssuerSigningKey())).build();
                    verifier.verify(Token);
                }
                res.setItem1(ResponseTypeEnum.Success);
            }
            String role=decodedJWT.getClaim("role").asString();
            List<String> roleList= Arrays.stream(authorize.roles())
                    .map(t->t.toString())
                    .collect(Collectors.toList());
            if (!roleList.contains(role)){
                res.setItem(false);
                res.setItem1(ResponseTypeEnum.IllegalPermission);
            }
            return res;

        }
        catch (Exception e){
            res.setItem(false);
            res.setItem1(ResponseTypeEnum.Exception);
            return res;
        }
    }

    public static <T> T getJwtInfo(String token,String key,Class<T> tClass){
        if(token==null){
            return null;
        }
        JWTVerifier build = JWT.require(Algorithm.HMAC256(staticJwtProp.getIssuerSigningKey())).build();
        DecodedJWT verify=build.verify(token);
        return JSONObject.parseObject(verify.getClaim(key).asString(), tClass);
    }



}
